package edu.iit.cs553;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class LocalExecutionManager {

	public double executeTasks(List<Map<Integer, Long>> workload, int numberOfLocalWorkers) throws InterruptedException
	{
		double totalExecutionTime = 0;
		double startTime = 0;
		double endTime = 0;
		Thread[] threads = initializeThreads(workload, numberOfLocalWorkers);

		startTime = System.currentTimeMillis();
		System.out.println(); // For log readability purposes
		for (int i = 0; i < threads.length; i++)
		{
			threads[i].start();
		}
		for (int j = 0; j < threads.length; j++)
		{
			threads[j].join();
		}
		endTime = System.currentTimeMillis();
		totalExecutionTime = endTime - startTime;
		return totalExecutionTime;
	}

	private Thread[] initializeThreads(List<Map<Integer, Long>> workload, int numberOfLocalWorkers)
	{
		Thread[] threads = new Thread[numberOfLocalWorkers];
		List<Map<Integer, Long>>[] workloadsPerThreads = getWorkloadsPerThreads(workload, numberOfLocalWorkers);
		for (int i = 0; i < numberOfLocalWorkers; i++)
		{
			Thread thread = new Thread(new LocalWorker(workloadsPerThreads[i]));
			threads[i] = thread;
		}
		return threads;
	}

	private List<Map<Integer, Long>>[] getWorkloadsPerThreads(List<Map<Integer, Long>> workload, int numberOfLocalWorkers)
	{
		@SuppressWarnings("unchecked")
		List<Map<Integer, Long>>[] workloadsPerThreads = new ArrayList[numberOfLocalWorkers];
		int numberOfTasks = workload.size();
		int numberOfTasksPerThread = numberOfTasks / numberOfLocalWorkers;
		int numberOfExtraTasks = numberOfTasks % numberOfLocalWorkers;

		int taskIndex = 0;
		// Allocating the tasks
		for (int i = 0; i < numberOfLocalWorkers; i++)
		{
			List<Map<Integer, Long>> workloadPerThread = new ArrayList<Map<Integer, Long>>();
			for (int j = taskIndex; j < taskIndex + numberOfTasksPerThread; j++)
			{
				workloadPerThread.add(workload.get(j));
			}
			workloadsPerThreads[i] = workloadPerThread;
			taskIndex += numberOfTasksPerThread;
		}
		// Allocating the extra tasks
		if (numberOfExtraTasks != 0)
		{
			for (int k = 0; k < numberOfExtraTasks; k++)
			{
				Map<Integer, Long> currentTask = workload.get(taskIndex + k);
				workloadsPerThreads[k].add(currentTask);
			}
		}
		return workloadsPerThreads;
	}
}
